LIVE
Stay Updated!
Give us access so we can send you notifications and tell you when the next match will be.
`; renderCategoryPills(); renderChannelList(); renderNowPlaying(); renderControls(); renderPlayerState(); setupVideoEvents(); if (currentChannel && playerState === 'idle') playChannel(currentChannel, false); } function setupVideoEvents() { const video = document.getElementById('video-player'); if (!video) return; video.addEventListener('play', () => { isPaused = false; renderControls(); renderCenterPlay(); showControlsMobile(); }); video.addEventListener('pause', () => { isPaused = true; renderControls(); renderCenterPlay(); showControlsMobile(); }); video.addEventListener('volumechange', () => { isMuted = video.muted; volume = video.volume; renderControls(); renderPlayerState(); }); const showAndHide = () => { const w = document.getElementById('player-wrapper'); if (w) { w.classList.add('show-controls'); w.classList.add('show-controls-mobile'); } clearTimeout(hideTimer); hideTimer = setTimeout(() => { if (w && !isPaused) { w.classList.remove('show-controls'); w.classList.remove('show-controls-mobile'); } }, 4000); }; const w = document.getElementById('player-wrapper'); if (w) { w.addEventListener('mousemove', showAndHide); w.addEventListener('touchstart', showAndHide, { passive: true }); showAndHide(); // On mobile: only toggle play/pause through center button or control bar // On desktop: single click toggles play let lastTap = 0; w.addEventListener('click', (e) => { // Always ignore clicks on controls/buttons if (e.target.closest('.player-controls') || e.target.closest('.unmute-btn') || e.target.closest('.retry-btn') || e.target.closest('.center-play-btn')) return; const now = Date.now(); // Double click = fullscreen on both mobile and desktop if (now - lastTap < 300) { toggleFullscreen(); return; } lastTap = now; // On desktop: single click toggles play // On mobile: single click only shows/hides controls, does NOT toggle play if (window.innerWidth >= 640) { setTimeout(() => { if (Date.now() - lastTap >= 280) { if (playerState === 'playing') togglePlay(); } }, 300); } // On mobile, single tap just shows controls (handled by touchstart above) }); } // ESC key exits landscape document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && isLandscapeMode) { exitLandscape(); } }); // Landscape overlay close button document.getElementById('landscape-close')?.addEventListener('click', exitLandscape); document.getElementById('lc-play')?.addEventListener('click', toggleLandscapePlay); document.getElementById('lc-mute')?.addEventListener('click', toggleLandscapeMute); // Sync landscape video state video.addEventListener('play', () => { if (isLandscapeMode) { const lVideo = document.getElementById('landscape-video'); if (lVideo) lVideo.play().catch(()=>{}); } }); video.addEventListener('pause', () => { if (isLandscapeMode) { const lVideo = document.getElementById('landscape-video'); if (lVideo) lVideo.pause(); } }); } function renderCenterPlay() { const btn = document.getElementById('center-play-btn'); if (!btn) return; if (isPaused && playerState === 'playing') { btn.classList.add('visible'); btn.innerHTML = ''; } else { btn.classList.remove('visible'); } } function showControlsMobile() { const w = document.getElementById('player-wrapper'); if (w) { w.classList.add('show-controls'); w.classList.add('show-controls-mobile'); } clearTimeout(hideTimer); hideTimer = setTimeout(() => { if (w && !isPaused) { w.classList.remove('show-controls'); w.classList.remove('show-controls-mobile'); } }, 4000); } function renderPlayerState() { const o = { idle: document.getElementById('overlay-idle'), loading: document.getElementById('overlay-loading'), error: document.getElementById('overlay-error') }; const u = document.getElementById('unmute-btn'); Object.values(o).forEach(el => { if (el) el.style.display = 'none'; }); if (playerState === 'idle' && o.idle) o.idle.style.display = 'flex'; if (playerState === 'loading' && o.loading) o.loading.style.display = 'flex'; if (playerState === 'error' && o.error) o.error.style.display = 'flex'; if (playerState === 'playing' && isMuted && u) u.style.display = 'flex'; if (playerState === 'playing' && !isMuted && u) u.style.display = 'none'; renderCenterPlay(); } function renderControls() { const pb = document.getElementById('btn-play'); const mb = document.getElementById('btn-mute'); const vr = document.getElementById('volume-range'); if (pb) pb.innerHTML = isPaused ? '' : ''; if (mb) { if (isMuted || volume === 0) mb.innerHTML = ''; else if (volume < 0.5) mb.innerHTML = ''; else mb.innerHTML = ''; } if (vr) vr.value = isMuted ? 0 : volume; } function renderCategoryPills() { const c = document.getElementById('cat-pills'); if (!c) return; const groups = getGroups(); c.innerHTML = groups.map(g => `` ).join(''); } function renderChannelList() { const c = document.getElementById('ch-list'); if (!c) return; if (filteredChannels.length === 0) { c.innerHTML = '
No channels found
'; return; } c.innerHTML = filteredChannels.map(ch => { const active = currentChannel && ch.id === currentChannel.id; const esc = ch.id.replace(/'/g, "\\'"); const logoHtml = ch.logo ? `` : `${getInitials(ch.name)}`; return `
${ch.group}
${ch.name}
`; }).join(''); } function renderNowPlaying() { const c = document.getElementById('now-playing-area'); if (!c) return; if (!currentChannel) { c.innerHTML = ''; return; } const ch = currentChannel; const logoHtml = ch.logo ? `` : `${getInitials(ch.name)}`; c.innerHTML = `
${ch.group}
${ch.name}
LIVE
`; } // Expose functions window._togglePlay = togglePlay; window._toggleMute = toggleMute; window._setVolume = setVolume; window._toggleFullscreen = toggleFullscreen; window._toggleLandscape = toggleLandscape; window._togglePiP = togglePiP; window._retryStream = retryStream; // Prefetch channel manifest on hover/touch for faster switching const _prefetchCache = new Set(); window._prefetchChannel = function(id) { const ch = channels.find(c => c.id === id); if (ch && ch.url && !_prefetchCache.has(ch.url)) { _prefetchCache.add(ch.url); fetch(ch.url, { mode: 'cors', method: 'GET', cache: 'force-cache' }).catch(() => {}); } }; window._onSearch = function(val) { searchQuery = val; filterChannels(); renderChannelList(); }; window._selectGroup = function(group) { currentGroup = group; filterChannels(); renderCategoryPills(); renderChannelList(); }; window._selectChannel = function(id) { const ch = channels.find(c => c.id === id); if (ch) { // If in landscape mode, exit first if (isLandscapeMode) exitLandscape(); playChannel(ch, true); } }; // Show notification popup after 5 minutes if (Notification && Notification.permission === 'default') { setTimeout(function() { var overlay = document.getElementById('notif-overlay'); if (overlay && Notification.permission === 'default') { overlay.classList.add('active'); } }, 5 * 60 * 1000); } // Enable button triggers browser notification permission document.getElementById('notif-enable-btn')?.addEventListener('click', function() { if ('Notification' in window) { Notification.requestPermission().then(function(perm) { var overlay = document.getElementById('notif-overlay'); if (overlay) overlay.classList.remove('active'); }); } }); fetchChannels(); })();